<html><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"><script type="text/x-mathjax-config;executed=true">MathJax.Hub.Config({tex2jax: {inlineMath: [ ['$','$'], ['\\(','\\)'] ],processEscapes:true}});</script><script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script><script type="text/javascript" src="chrome-extension://febilkbfcbhebfnokafefeacimjdckgl/js/runMathJax.js"></script><link rel="stylesheet" id="theme" href="chrome-extension://febilkbfcbhebfnokafefeacimjdckgl/theme/Github.css"><style type="text/css">.MathJax_Hover_Frame {border-radius: .25em; -webkit-border-radius: .25em; -moz-border-radius: .25em; -khtml-border-radius: .25em; box-shadow: 0px 0px 15px #83A; -webkit-box-shadow: 0px 0px 15px #83A; -moz-box-shadow: 0px 0px 15px #83A; -khtml-box-shadow: 0px 0px 15px #83A; border: 1px solid #A6D ! important; display: inline-block; position: absolute}
.MathJax_Hover_Arrow {position: absolute; width: 15px; height: 11px; cursor: pointer}
</style><style type="text/css">#MathJax_About {position: fixed; left: 50%; width: auto; text-align: center; border: 3px outset; padding: 1em 2em; background-color: #DDDDDD; color: black; cursor: default; font-family: message-box; font-size: 120%; font-style: normal; text-indent: 0; text-transform: none; line-height: normal; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; z-index: 201; border-radius: 15px; -webkit-border-radius: 15px; -moz-border-radius: 15px; -khtml-border-radius: 15px; box-shadow: 0px 10px 20px #808080; -webkit-box-shadow: 0px 10px 20px #808080; -moz-box-shadow: 0px 10px 20px #808080; -khtml-box-shadow: 0px 10px 20px #808080; filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')}
.MathJax_Menu {position: absolute; background-color: white; color: black; width: auto; padding: 2px; border: 1px solid #CCCCCC; margin: 0; cursor: default; font: menu; text-align: left; text-indent: 0; text-transform: none; line-height: normal; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; z-index: 201; box-shadow: 0px 10px 20px #808080; -webkit-box-shadow: 0px 10px 20px #808080; -moz-box-shadow: 0px 10px 20px #808080; -khtml-box-shadow: 0px 10px 20px #808080; filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')}
.MathJax_MenuItem {padding: 2px 2em; background: transparent}
.MathJax_MenuArrow {position: absolute; right: .5em; color: #666666}
.MathJax_MenuActive .MathJax_MenuArrow {color: white}
.MathJax_MenuArrow.RTL {left: .5em; right: auto}
.MathJax_MenuCheck {position: absolute; left: .7em}
.MathJax_MenuCheck.RTL {right: .7em; left: auto}
.MathJax_MenuRadioCheck {position: absolute; left: 1em}
.MathJax_MenuRadioCheck.RTL {right: 1em; left: auto}
.MathJax_MenuLabel {padding: 2px 2em 4px 1.33em; font-style: italic}
.MathJax_MenuRule {border-top: 1px solid #CCCCCC; margin: 4px 1px 0px}
.MathJax_MenuDisabled {color: GrayText}
.MathJax_MenuActive {background-color: Highlight; color: HighlightText}
.MathJax_Menu_Close {position: absolute; width: 31px; height: 31px; top: -15px; left: -15px}
</style><style type="text/css">.MathJax_Preview .MJXc-math {color: inherit!important}
</style><style type="text/css">#MathJax_Zoom {position: absolute; background-color: #F0F0F0; overflow: auto; display: block; z-index: 301; padding: .5em; border: 1px solid black; margin: 0; font-weight: normal; font-style: normal; text-align: left; text-indent: 0; text-transform: none; line-height: normal; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; box-shadow: 5px 5px 15px #AAAAAA; -webkit-box-shadow: 5px 5px 15px #AAAAAA; -moz-box-shadow: 5px 5px 15px #AAAAAA; -khtml-box-shadow: 5px 5px 15px #AAAAAA; filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')}
#MathJax_ZoomOverlay {position: absolute; left: 0; top: 0; z-index: 300; display: inline-block; width: 100%; height: 100%; border: 0; padding: 0; margin: 0; background-color: white; opacity: 0; filter: alpha(opacity=0)}
#MathJax_ZoomFrame {position: relative; display: inline-block; height: 0; width: 0}
#MathJax_ZoomEventTrap {position: absolute; left: 0; top: 0; z-index: 302; display: inline-block; border: 0; padding: 0; margin: 0; background-color: white; opacity: 0; filter: alpha(opacity=0)}
</style><style type="text/css">.MathJax_Preview {color: #888}
#MathJax_Message {position: fixed; left: 1em; bottom: 1.5em; background-color: #E6E6E6; border: 1px solid #959595; margin: 0px; padding: 2px 8px; z-index: 102; color: black; font-size: 80%; width: auto; white-space: nowrap}
#MathJax_MSIE_Frame {position: absolute; top: 0; left: 0; width: 0px; z-index: 101; border: 0px; margin: 0px; padding: 0px}
.MathJax_Error {color: #CC0000; font-style: italic}
</style><style type="text/css">.MJXc-script {font-size: .8em}
.MJXc-right {-webkit-transform-origin: right; -moz-transform-origin: right; -ms-transform-origin: right; -o-transform-origin: right; transform-origin: right}
.MJXc-bold {font-weight: bold}
.MJXc-italic {font-style: italic}
.MJXc-scr {font-family: MathJax_Script,'Times New Roman',Times,STIXGeneral,serif}
.MJXc-frak {font-family: MathJax_Fraktur,'Times New Roman',Times,STIXGeneral,serif}
.MJXc-sf {font-family: MathJax_SansSerif,'Times New Roman',Times,STIXGeneral,serif}
.MJXc-cal {font-family: MathJax_Caligraphic,'Times New Roman',Times,STIXGeneral,serif}
.MJXc-mono {font-family: MathJax_Typewriter,'Times New Roman',Times,STIXGeneral,serif}
.MJXc-largeop {font-size: 150%}
.MJXc-largeop.MJXc-int {vertical-align: -.2em}
.MJXc-math {display: inline-block; line-height: 1.2; text-indent: 0; font-family: 'Times New Roman',Times,STIXGeneral,serif; white-space: nowrap; border-collapse: collapse}
.MJXc-display {display: block; text-align: center; margin: 1em 0}
.MJXc-math span {display: inline-block}
.MJXc-box {display: block!important; text-align: center}
.MJXc-box:after {content: " "}
.MJXc-rule {display: block!important; margin-top: .1em}
.MJXc-char {display: block!important}
.MJXc-mo {margin: 0 .15em}
.MJXc-mfrac {margin: 0 .125em; vertical-align: .25em}
.MJXc-denom {display: inline-table!important; width: 100%}
.MJXc-denom > * {display: table-row!important}
.MJXc-surd {vertical-align: top}
.MJXc-surd > * {display: block!important}
.MJXc-script-box > *  {display: table!important; height: 50%}
.MJXc-script-box > * > * {display: table-cell!important; vertical-align: top}
.MJXc-script-box > *:last-child > * {vertical-align: bottom}
.MJXc-script-box > * > * > * {display: block!important}
.MJXc-mphantom {visibility: hidden}
.MJXc-munderover {display: inline-table!important}
.MJXc-over {display: inline-block!important; text-align: center}
.MJXc-over > * {display: block!important}
.MJXc-munderover > * {display: table-row!important}
.MJXc-mtable {vertical-align: .25em; margin: 0 .125em}
.MJXc-mtable > * {display: inline-table!important; vertical-align: middle}
.MJXc-mtr {display: table-row!important}
.MJXc-mtd {display: table-cell!important; text-align: center; padding: .5em 0 0 .5em}
.MJXc-mtr > .MJXc-mtd:first-child {padding-left: 0}
.MJXc-mtr:first-child > .MJXc-mtd {padding-top: 0}
.MJXc-mlabeledtr {display: table-row!important}
.MJXc-mlabeledtr > .MJXc-mtd:first-child {padding-left: 0}
.MJXc-mlabeledtr:first-child > .MJXc-mtd {padding-top: 0}
.MJXc-merror {background-color: #FFFF88; color: #CC0000; border: 1px solid #CC0000; padding: 1px 3px; font-style: normal; font-size: 90%}
.MJXc-scale0 {-webkit-transform: scaleX(.0); -moz-transform: scaleX(.0); -ms-transform: scaleX(.0); -o-transform: scaleX(.0); transform: scaleX(.0)}
.MJXc-scale1 {-webkit-transform: scaleX(.1); -moz-transform: scaleX(.1); -ms-transform: scaleX(.1); -o-transform: scaleX(.1); transform: scaleX(.1)}
.MJXc-scale2 {-webkit-transform: scaleX(.2); -moz-transform: scaleX(.2); -ms-transform: scaleX(.2); -o-transform: scaleX(.2); transform: scaleX(.2)}
.MJXc-scale3 {-webkit-transform: scaleX(.3); -moz-transform: scaleX(.3); -ms-transform: scaleX(.3); -o-transform: scaleX(.3); transform: scaleX(.3)}
.MJXc-scale4 {-webkit-transform: scaleX(.4); -moz-transform: scaleX(.4); -ms-transform: scaleX(.4); -o-transform: scaleX(.4); transform: scaleX(.4)}
.MJXc-scale5 {-webkit-transform: scaleX(.5); -moz-transform: scaleX(.5); -ms-transform: scaleX(.5); -o-transform: scaleX(.5); transform: scaleX(.5)}
.MJXc-scale6 {-webkit-transform: scaleX(.6); -moz-transform: scaleX(.6); -ms-transform: scaleX(.6); -o-transform: scaleX(.6); transform: scaleX(.6)}
.MJXc-scale7 {-webkit-transform: scaleX(.7); -moz-transform: scaleX(.7); -ms-transform: scaleX(.7); -o-transform: scaleX(.7); transform: scaleX(.7)}
.MJXc-scale8 {-webkit-transform: scaleX(.8); -moz-transform: scaleX(.8); -ms-transform: scaleX(.8); -o-transform: scaleX(.8); transform: scaleX(.8)}
.MJXc-scale9 {-webkit-transform: scaleX(.9); -moz-transform: scaleX(.9); -ms-transform: scaleX(.9); -o-transform: scaleX(.9); transform: scaleX(.9)}
.MathJax_CHTML .noError {vertical-align: ; font-size: 90%; text-align: left; color: black; padding: 1px 3px; border: 1px solid}
</style><script type="text/javascript" src="chrome-extension://febilkbfcbhebfnokafefeacimjdckgl/js/runMathJax.js"></script><script type="text/javascript" src="chrome-extension://febilkbfcbhebfnokafefeacimjdckgl/js/runMathJax.js"></script><script type="text/javascript" src="chrome-extension://febilkbfcbhebfnokafefeacimjdckgl/js/runMathJax.js"></script></head><body><h1 id="-azure">Настройка мобильной службы Azure</h1>
<hr>
<p>В данной работе вы настроите мобильную службу Azure для использования в последующих работах.</p>
<h2 id="-">Создание мобильной службы</h2>
<ol>
<li><p>Зайдите на <a href="http://manage.windowsazure.com">портал Microsoft Azure</a>, используя вашу учетную запись.</p>
</li>
<li><p>Перейдите в раздел <strong>Мобильные службы</strong> и нажмите кнопку <strong>Создать</strong> слева внизу страницы.</p>
</li>
<li><p>В появившемся меню снова выберите <strong>Создать</strong> и в появившейся форма введите название мобильной службы (придумайте свое, 
в дальнейшем мы будем ссылаться на него как <em>&lt;имя вашей мобильной службы&gt;</em>). Имя должно быть уникальным. Если это не так, вы увидите восклицательный знак справа от поля ввода. Выберите регион, который ближе всего к вам, а тип сервера - <strong>JavaScript</strong>. Настройте остальные параметры по своему усмотрению. Если затрудняетесь, 
оставьте их, как на рисунке ниже.
</p><p align="center"><img src="images\new_mob_service_1.jpg" width="80%/"></p>
Перейдите ко второму шагу мастера, нажав справа внизу кнопку со стрелкой.<p></p>
</li>
<li><p>На втором шаге в поле <strong>Имя</strong> укажите имя базы данных для мобильной службы. Ниже вы можете выбрать существующий сервер SQL или создать новый. Для целей данного руководства мы создадим новый сервер (выберите <strong>Создать сервер базы данных SQL</strong>). Придумайте имя и пароль для входа на сервер и введите их в соответствующие поля. Выберите регион и настройте остальные параметры. Если затрудняетесь, оставьте их как на рисунке ниже (однако, вам все же придется придумать пароль). Нажмите кнопку с галочкой.</p>
<p align="center"><img src="images\new_mob_service_2.jpg" width="80%/"></p>
</li>
<li><p>По завершению создания мобильной службы в соответствующей панели появится информация о ней.</p>
<p align="center"><img src="images\mob_service_info.jpg" width="90%/"></p>

</li>
</ol>
<h2 id="-">Создание таблицы для хранения данных</h2>
<ol>
<li><p>Кликните по названию мобильной службы. Вы попадете на стартовый экран мобильной службы.</p>
</li>
<li><p>В строке меню кликните пункт <strong>Данные</strong> и на появившейся странице - <strong>Добавить таблицу</strong>.</p>
</li>
<li><p>На странице появившегося мастера укажите имя таблицы (вам необходимо придумать свое, в дальнейшем будем ссылаться на него как <em>&lt;имя вашей таблицы данных&gt;</em>). Остальные параметры установите, как на рисунке. Нажмите кнопку с галочкой.
</p><p align="center"><img src="images\mob_service_new_table.jpg" width="90%/"></p><p></p>
<blockquote>
<p><strong>Важно:</strong> В дальнейшем имя таблицы будет использовано в исходном коде мобильного приложения на C#, поэтому старайтесь выбрать такое имя, которое не приведет к соответствующим конфликтам. Если сомневаетесь, выберите имя, указанное на рисунке.</p>
</blockquote>
</li>
<li><p>Кликните по имени созданной таблицы, чтобы перейти к ее настройке. Откроется страница <strong>Обзор</strong> с сообщением об отсутствии записей.</p>
</li>
</ol>
<h2 id="-">Настройка разрешений таблицы</h2>
<p>Перейдите к странице <strong>Разрешения</strong> и убедитесь, что для таблицы установлены разрешения, как на рисунке ниже. Если это не так, установите их, чтобы они соответствовали рисунку.</p>
<p align="center"><img src="images\table_permissions.jpg" width="90%/"></p>

<h2 id="-">Создание столбцов</h2>
<ol>
<li><p>Перейдите к странице <strong>Столбцы</strong> и ознакомьтесь со столбцами, создаваемыми по умолчанию.</p>
</li>
<li><p>Внизу страницы нажмите <strong>Добавить столбец</strong> и в появившемся окне выберите тип данных <strong>String</strong>, а имя столбца укажите <strong>deviceid</strong>. В этом столбце будет храниться строковый идентификатор устройства. Нажмите кнопку с галочкой, чтобы добавить столбец.</p>
</li>
<li><p>Аналогично предыдущему пункту добавьте в таблицу столбец <strong>userid</strong> типа <strong>string</strong> и столбцы <strong>t</strong>, <strong>rh</strong>, <strong>led0</strong>, <strong>led1</strong> типа <strong>number</strong>. Информация о будущем использовании всех столбцов приведена ниже.</p>
</li>
</ol>
<table>
<thead>
<tr>
<th><strong>Имя столбца</strong></th>
<th><strong>Назначение</strong></th>
<th><strong>Направление данных</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>deviceid</td>
<td>Идентификатор устройства</td>
<td>От tessel в таблицу</td>
</tr>
<tr>
<td>userid</td>
<td>Идентификатор пользователя - зарезервировано для будущего использования</td>
<td>От tessel в таблицу</td>
</tr>
<tr>
<td>t</td>
<td>Температура воздуха в °C</td>
<td>От tessel в таблицу</td>
</tr>
<tr>
<td>rh</td>
<td>Относительная влажность воздуха в %</td>
<td>От tessel в таблицу</td>
</tr>
<tr>
<td>led0</td>
<td>Состояние первого светодиода tessel</td>
<td>От таблицы к tessel</td>
</tr>
<tr>
<td>led1</td>
<td>Состояние второго светодиода tessel</td>
<td>От таблицы к tessel</td>
</tr>
</tbody>
</table>
<p>После создания столбцов страница <strong>Столбцы</strong> в Azure будет выглядеть, как показано на рисунке ниже.</p>
<p align="center"><img src="images\table_columns.jpg" width="90%/"></p>

<h2 id="-api-">Создание и настройка API мобильной службы</h2>
<ol>
<li><p>От интерфейса таблицы перейдите к мобильной службе, нажав круглую кнопку со стрелкой "Назад".</p>
</li>
<li><p>Кликните на странице <strong>API</strong>, а затем - <strong>Создать настраиваемый API</strong>.</p>
</li>
<li><p>На появившейся странице мастера введите имя API (вам нужно придумать свое уникальное имя, в дальнейшем будем ссылаться на него как <em>&lt;имя вашего мобильного API&gt;</em>). Установите разрешения для API, как указано на рисунке ниже и нажмите кнопку с галочкой.</p>
<p align="center"><img src="images\api_permissions.jpg" width="90%/"></p>
</li>
<li><p>Кликните по имени созданного API. Вы попадете на страницу <strong>Скрипт</strong>. Здесь вы можете ввести код скрипта на JavaScript, который выполняется при осуществлении GET-запроса по адресу <strong>http://&lt;имя вашей мобильной службы&gt;.azure-mobile.net/api/&lt;имя вашего API&gt;</strong>, например, если в точности следовать рисункам в данном руководстве, то получится адрес <strong><a href="http://tessel-demo.azure-mobile.net/api/dev_api">http://tessel-demo.azure-mobile.net/api/dev_api</a></strong>. Если вы не знакомы с протоколом HTTP и не знаете, что такое GET-запрос, ознакомьтесь <a href="https://ru.wikipedia.org/wiki/HTTP">со статьей</a>.</p>
</li>
<li><p>Удалите весь код из окна <strong>Скрипт</strong> и скопируйте на его место код из материалов руководства <a href="code\api.js">api.js</a>. Ознакомьтесь с кодом.</p>
</li>
<li><p>Найдите в начале кода строку</p>
<pre><code>var table_name = "<span class="tag">&lt;<span class="title">put</span> <span class="attribute">your</span> <span class="attribute">table</span> <span class="attribute">name</span> <span class="attribute">here</span>&gt;</span>";
</code></pre><p>и отредактируйте ее, поместив в переменную название вашей таблицы мобильной службы. Внизу экрана нажмите кнопку <strong>Сохранить</strong>.</p>
</li>
</ol>
<h2 id="-">Проверка работы мобильной службы с помощью браузера</h2>
<ol>
<li><p>Запустите любой браузер (или создайте вкладку, если браузер открыт) и наберите в строке URL, заменив идентификаторы в угловых скобках на идентификаторы, соответствующие вашей службе:</p>
<pre><code>http://<span class="tag">&lt;<span class="title">имя</span> вашей мобильной службы&gt;</span>.azure-mobile.net/api/<span class="tag">&lt;<span class="title">имя</span> вашего <span class="attribute">API</span>&gt;</span>
</code></pre><p>например:</p>
<pre><code><span class="symbol">http:</span>/<span class="regexp">/tessel-demo.azure-mobile.net/api</span><span class="regexp">/dev_api
</span></code></pre><p>В зависимости от браузера и его настроек, вы можете увидеть одно из сообщений, показанных на рисунках ниже (код 403 или 
сообщение <em>{"message":"No device"}</em> - признак правильной работы скрипта).
</p><p align="center"><img src="images\nodevice_403.jpg" width="90%/"></p>
<p align="center"><img src="images\nodevice_json.jpg"></p><p></p>
<blockquote>
<p>Скрипт передает сообщение в элементе JSON. Это необходимо для обеспечения совместимости с любыми IoT-устройствами, пользующимися API, так как они будут ожидать от сервиса ответ именно в таком формате. При этом свойство Content-Type устанавливается в text/plain, что облегчает ознакомление со скриптом при использовании браузера.</p>
</blockquote>
</li>
<li><p>Проверьте работу скрипта, набрав URL</p>
<pre><code>http://<span class="tag">&lt;<span class="title">имя</span> вашей мобильной службы&gt;</span>.azure-mobile.net/api/<span class="tag">&lt;<span class="title">имя</span> вашего <span class="attribute">API</span>&gt;</span>?deviceid=test_id&amp;t=0.0&amp;rh=0.0
</code></pre><p>В браузере появится сообщение, показанное на рисунке ниже.</p>
<p align="center"><img src="images\api_created.jpg"></p>
</li>
<li><p>Наберите еще раз тот же URL. На этот раз в браузере появятся данные, возвращенные API. Поскольку мы ранее не задавали значения для столбцов led0, led1, то они будут обозначены как пустые (null).</p>
<p align="center"><img src="images\api_data.jpg"></p>
</li>
<li><p>Вернитесь к порталу управления Azure и выберите мобильную службу. Перейдите на страницу <strong>Журналы</strong>. Убедитесь, что скрипт выполнил журналирование операций.</p>
</li>
</ol>
<h2 id="-">Обсуждение</h2>
<h4 id="-iot-azure">Почему для обмена с IoT-устройством используется таблица мобильных служб, а не другие варианты хранилищ данных Azure</h4>
<p>Сохранение данных в таблице мобильной службы Azure позволяет с легкостью передавать их в мобильное приложение.</p>
<h4 id="-">Почему поле идентификатора пользователя зарезервировано для будущего использования</h4>
<p>Вам будет предложено добавить аутентификацию пользователей в конце данного руководства. Таблица уже будет готова к этому.</p>
<h4 id="-iot-azure-">Почему IoT устройство предполагается использовать как клиент, подключающийся к службам Azure, а не веб-сервер с прямой отдачей данных</h4>
<ul>
<li>При наличии большого количества таких устройств представление каждого в виде сервера значительно усложнит сбор данных и централизованное управление;</li>
<li>Если устройства используются не в локальной сети, а в Интернет, каждому из них понадобится внешний IP-адрес или соответствующая настройка сетевого оборудования, что вызовет дополнительные сложности;</li>
<li>Подключение большого количества устройств к одной службе Azure позволяет централизованно собирать с них данные и передавать их в другие службы Azure и мобильные приложения, а также централизованно управлять устройствами.</li>
</ul>
<h4 id="-api-rest-api">Зачем нужен собственный API мобильной службы, если существует готовый REST API</h4>
<ul>
<li>Использование собственного API проще и понятнее для реализации соединения IoT-устройства и мобильной службы, особенно при наличии аутентификации пользователей;</li>
<li>Дополнительное преимущество: скрытие ненужных для IoT-устройства деталей API при реализации собственного API.</li>
</ul>
<h2 id="-">Пути улучшения (не обязательно к выполнению)</h2>
<ol>
<li><p>Подумайте, какие преимущества может иметь использование POST вместо GET-запроса.</p>
</li>
<li><p>Обратите внимание, что в скрипте API были использованы SQL запросы, а не работа с таблицами напрямую с помощью express.JS. Второй подход может быть оптимальнее, если вы знакомы с express.JS. Подумайте, как реализовать второй подход в данном случае.</p>
</li>
<li><p>Подумайте над безопасностью данного решения. Можно ли ее улучшить?</p>
</li>
</ol>
</body></html>